// https://xue.kaikeba.com/interactive-course/12113
// 灌溉
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <sstream>
#include <map>
#include <vector>
#include <set>
#include <unordered_map>
#include <time.h>
#include <stdint.h>
#include <queue>
#include <unordered_set>
#include <stack>

using namespace std;

const int maxn = 500 + 10;
const int inf = 0x3f3f3f3f;

int n, x;
int mp[maxn][maxn]; // 邻接矩阵
int vis[maxn], dis[maxn]; // vis 哪些点在G集合, 哪些在T集合, dis G中与T可达的点距离

void prim() {
    vis[1] = 1; // 1节点加入到我们的T集合中去
    for(int i = 1; i <= n; i++) {
        dis[i] = mp[1][i]; // G集合中的点到T集合中的距离
    }

    for(int i = 2; i <= n; i++) { // 遍历所有的点
        int minn = inf, v = -1; // v是我们找到的点
        for(int j = 1; j <= n; j++) {
            if(!vis[j] && minn > dis[j]) {
                minn = dis[j];
                v = j;
            }
        }
        vis[v] = 1;

        // 遍历所有非T集合中的点, 更新这些点到集合中的距离
        for(int j = 1; j <= n; j++) {
            if(!vis[j] && dis[j] > mp[v][j]) {
                dis[j] = mp[v][j];
            }
        }
    }

    int sum = 0;
    for(int i = 1; i <= n; i++) {
        sum += dis[i];
    }
    printf("%d\n", sum);

    return ;
}


int main() {

    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            scanf("%d", &x);
            mp[i][j] = x;
        }
    }

    prim();


    return 0;
}

